package cn.tpshion.devops.node;

import cn.tpshion.devops.common.constant.RedisKey;
import cn.tpshion.devops.common.enums.NodeType;
import cn.tpshion.devops.common.constant.NodeConstant;
import cn.tpshion.devops.domain.entity.NodeData;
import cn.tpshion.devops.domain.entity.SSHSecretData;
import cn.tpshion.devops.domain.entity.SecretData;
import cn.tpshion.devops.handle.SSHHandle;
import cn.tpshion.devops.node.data.DockerData;
import cn.tpshion.devops.node.data.SSHData;
import cn.tpshion.devops.node.support.NodeContext;
import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@Slf4j
@Component
public class DockerNode extends Node<DockerData>{

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Override
    public NodeType nodeType() {
        return NodeType.DOCKER;
    }

    @Override
    public void handle(NodeContext nodeContext) throws Exception {
        log.info("DockerNode nodeContext:{}", nodeContext);
        Map<String, Object> contextData = nodeContext.getData();
        DockerData data = getData(nodeContext);

        StringBuilder builder = new StringBuilder();
        builder.append("docker build -t ");
        if(StringUtils.hasText(data.getRegistry())){
            builder.append(data.getRegistry() + "/");
        }
        builder.append(data.getName() + ":" + data.getTag());
        builder.append(" -f " + getDockerFilePath(contextData, data) + " " + data.getBuildPath());
        String command = builder.toString();
        log.info("DockerNode command:{}", command);

        SSHData sshData = new SSHData();
        sshData.setHost(data.getHost());
        sshData.setUsername(data.getUsername());
        sshData.setPassword(data.getPassword());
        sshData.setPort(data.getPort());

        try (SSHHandle sshHandle = new SSHHandle(sshData, sseHandle, nodeContext)){
            sshHandle.exec(getExecCommand(data, command, sshHandle));
            handleSingleCommand(sshHandle, data.getSingleCommand());
        }
    }

    private String getExecCommand(DockerData data, String dockerCommand, SSHHandle sshHandle){
        StringBuilder builder = new StringBuilder();
        // 获取前置命令
        if(StringUtils.hasText(data.getBeforeCommand())){
            List<String> beforeList = sshHandle.handleCommandStr(data.getBeforeCommand());
            beforeList.forEach(i -> builder.append(i + " && "));
        }

        builder.append(dockerCommand);

        // 获取后置命令
        if(StringUtils.hasText(data.getAfterCommand())){
            List<String> afterList = sshHandle.handleCommandStr(data.getAfterCommand());
            afterList.forEach(i -> builder.append(" && " + i));
        }
        return builder.toString();
    }

    private void handleSingleCommand(SSHHandle sshHandle, String command) throws Exception{
        if(!StringUtils.hasText(command) || Objects.isNull(sshHandle)){
            return;
        }
        for (String singleCommand : sshHandle.handleCommandStr(command)) {
            sshHandle.exec(singleCommand);
        }
    }

    private String getDockerFilePath(Map<String, Object> contextData, DockerData data){
        String workspace = contextData.get(NodeConstant.WORKSPACE).toString();
        String dockerFile = data.getDockerFile();
        if(!StringUtils.hasText(dockerFile)){
            return "Dockerfile";
        }
        if(dockerFile.contains("#workspace#")){
            return dockerFile.replaceAll("#workspace#", workspace);
        }
        return dockerFile;
    }

    @Override
    protected DockerData getData(NodeContext nodeContext) {
        NodeData nodeData = nodeContext.getNodeData();
        DockerData data = JSON.parseObject(JSON.toJSONString(nodeData.getData()), DockerData.class);

        HashOperations<String, String, String> hash = redisTemplate.opsForHash();
        String value = hash.get(RedisKey.SECRET, data.getSecretName());
        SecretData secretData = JSON.parseObject(value, SecretData.class);

        SSHSecretData sshSecretData = JSON.parseObject(JSON.toJSONString(secretData.getData()), SSHSecretData.class);
        data.setHost(sshSecretData.getHost());
        data.setUsername(sshSecretData.getUsername());
        data.setPassword(sshSecretData.getPassword());
        data.setPort(sshSecretData.getPort());
        return data;
    }
}
